/*
 * utils.c
 *
 *  Created on: 19/apr/2014
 *      Author: kappa
 */


#include "commons.h"
#include "semaphores.h"

#include "../cmd.h"

/********************************************************
 * @function 	: isNull								*
 * @descr		: Verifica se un puntatore punta NULL	*
 * @param ptr	: puntatore da  verificare				*
 * @return		: 1 se ptr punta NULL, 0 altrimenti		*
 ********************************************************/
int isNull(void *ptr){
	if(ptr == NULL)
		return 1;
	else return 0;
}

/************************************************************************
 * @function 		: getMemory											*
 * @descr			: Alloca un array di celle di memoria 				*
 * 					  del tipo descritto da sizeType e 					*
 * 					  nella quantita' indicata da size					*
 * @param size		: dimensione dell'array 							*
 * @param sizeType	: tipo di celle da allocare							*
 * @return			: un puntatore al primo elemento dell'array. Il		*
 * 					  puntatore richiede un cast obbligatorio al 		*
 * 					  tipo richiesto.									*
 * 					  In caso di errore viene invocata in modo bloccante*
 * 					  la funzione notifyError()[errors.c]				*
 ************************************************************************/
void * getMemory(int size, TYPE type){
	void *pointer = NULL;

	//Nessun log qui oppure va in loop con le chiamate (logMessage usa getMemory)
	switch(type){
		case INT_TYPE:
			pointer = malloc(sizeof(int)*size);
			break;
		case CHAR_TYPE:
			pointer = (void *)malloc(sizeof(char)*size);
			break;
		case FLOAT_TYPE:
			pointer = (void *)malloc(sizeof(float)*size);
			break;
		case DOUBLE_TYPE:
			pointer = (void *)malloc(sizeof(double)*size);
			break;
		case PINT_TYPE:
			pointer = (void *)malloc(sizeof(int*)*size);
			break;
		case PCHAR_TYPE:
			pointer = (void *)malloc(sizeof(char*)*size);
			break;
		case PFLOAT_TYPE:
			pointer = (void *)malloc(sizeof(float*)*size);
			break;
		case PDOUBLE_TYPE:
			pointer = (void *)malloc(sizeof(double*)*size);
			break;
		case PVOID_TYPE:
			pointer = (void *)malloc(sizeof(void*)*size);
			break;

		case UINT_TYPE:
			pointer = (void *)malloc(sizeof(unsigned int)*size);
			break;

		case ULONG_TYPE:
			pointer = (void *)malloc(sizeof(unsigned long)*size);
			break;
/*Per i casi prettamente windows, prima di rimuoverli aspetto di
 * vedere se sono realmente necessari, anche se non credo.*/
#ifdef _WIN32
		case LPDWORD_TYPE:
			pointer = (void *)malloc(sizeof(LPDWORD)*size);
			break;
#endif
		case CNF_PTR_TYPE:
			pointer = (void *)malloc(sizeof(CNF_PTR)*size);
			break;

		case MAILCMD_TYPE:
			pointer = (void *)malloc(sizeof(MAILCMD)*size);
			break;

		case ARPAMSG_TYPE:
			pointer = (void *)malloc(sizeof(ARPAMESSAGE)*size);
			break;

		case MBXSEM_TYPE:
			pointer = (void *)malloc(sizeof(MBXSEM)*size);
			break;

		case PMBXSEM_TYPE:
			pointer = (void *)malloc(sizeof(PMBXSEM)*size);
			break;

		case PPMBXSEM_TYPE:
		pointer = (void *)malloc(sizeof(PPMBXSEM)*size);
		break;

		default:
			break;
	}
	if (isNull(pointer)==1){
		notifyError(ERR_NO_MEM,1,0);
		exit(-1);
	}
	return pointer;
} 



/************************************************************************
 * @function 		: createDir											*
 * @descr			: crea una directory 								*
 * 					  del tipo descritto da sizeType e 					*
 * 					  nella quantita' indicata da size.					*
 * @param dirname	: dimensione dell'array 							*
 * @return			: un puntatore al primo elemento dell'array. Il		*
 * 					  puntatore richiede un cast obbligatorio al 		*
 * 					  tipo richiesto.									*
 * 					  In caso di errore viene invocata in modo bloccante*
 * 					  la funzione notifyError()[errors.c]				*
 ************************************************************************/

void createDir(char *dirname){
#ifdef _WIN32
	if(!CreateDirectory(dirname, NULL)){
		errparams = (char**) getMemory(1,PCHAR_TYPE);
		errparams[0] = dirname;
		notifyError(ERR_DIR_OPEN, errparams,1,1);
	}
#else
	struct stat st = {0};
	//Se non esiste la directory la creo
	if (stat(dirname, &st) == -1) {
		if(mkdir(dirname, 0700)==-1){
			notifyError(ERR_DIR_OPEN,1,1, dirname);
		}
	}
#endif
		
}


/************************************************************************
 * @function 		: decodeMode										*
 * @descr			: decodifica la modalit� di apertura di uno stream 	*
 * 					  da crossplatform a platform dependant sui sitemi 	*
 * 					  unix-like e windows.								*
 * @param mode		: Modalita' di apertura dello stream 				*
 * @return			: un long contente gli specifici flags per i sistemi*
 * 					  windows e unix-like.								*
 ************************************************************************/
long decodeMode(MODE mode){
	long modus = 0L;

	switch(mode){

	case READ:
		#ifdef _WIN32
			modus = (long)GENERIC_READ;
		#else
			modus = (long)O_RDONLY;
		#endif
		break;

	case WRITE:
		#ifdef _WIN32
			modus = (long)GENERIC_READ|GENERIC_WRITE;
		#else
			modus = (long)O_RDWR;
		#endif
		break;

	case WTRUNC:
		#ifdef _WIN32
			modus = (long)GENERIC_READ|GENERIC_WRITE;
		#else
			modus = (long)O_RDWR | O_TRUNC;
		#endif
		break;

	default:
		notifyError(ERR_DEC_MOD, 0, 0);
		break;
	}
	return modus;
}

/****************************************************************************
 * @function 		: openFile												*
 * @descr			: Apre un file esistente.  								*
 * @param filename	: in windows il nome del file da aprire, in unix-like	*
 *					  il nome file corredato del suo path.					*
 * @param mode		: modalita' di apertura dello stream					*
 * @param exitonerr	: indica il comportamento in caso di errore.			*
 *					  0 = non bloccante, 1 = bloccante.						*
 *					  Se la chiamata e' bloccante causa l'interruzione del	*
 *					  programma												*
 * @return			: il filehandle associato al file o NULL in caso di		*
 *					  chiamata non bloccante con errore 						*
 ****************************************************************************/
void * openFile(char *filename, MODE mode, int exitonerr){

	void* filehandle = NULL;

	#ifdef _WIN32
	
	/*Provo ad aprire il file esistente*/
	filehandle =(void*) CreateFile(filename, decodeMode(mode),
									0,NULL,OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL,NULL);
	if((HANDLE)filehandle == INVALID_HANDLE_VALUE){
		errparams = (char**) getMemory(1,PCHAR_TYPE);
		errparams[0] = filename;
		notifyError(ERR_FILE_OPEN, errparams,1,exitonerr);
		free(filehandle);
		filehandle = NULL;
	}
	#else
	
	filehandle = (void *) getMemory(1,INT_TYPE);
	*(int *)filehandle = open(filename,decodeMode(mode),S_IRWXU);
	if(*(int *)filehandle == -1){
		notifyError(ERR_FILE_OPEN, exitonerr, 1, filename);
		free(filehandle);
		filehandle = NULL;
	}
	#endif // DEBUG
	return filehandle;
}



/****************************************************************************
 * @function 		: createFile											*
 * @descr			: Crea un file.			  								*
 * @param filename	: in windows il nome del file da aprire, in unix-like	*
 *					  il nome file corredato del suo path.					*
 * @param mode		: modalita' di apertura dello stream					*
 * @param exitonerr	: indica il comportamento in caso di errore.			*
 *					  0 = non bloccante, 1 = bloccante.						*
 *					  Se la chiamata e' bloccante causa l'interruzione del	*
 *					  programma												*
 * @return			: il filehandle associato al file creato o NULL in caso *
 *					  di chiamata non bloccante con errore					*
 ****************************************************************************/
void * createFile(char *filename, MODE mode, int exitonerr){

	void* filehandle = NULL;
	
#ifdef _WIN32
	filehandle =(void*) CreateFile(filename, decodeMode(mode),0,NULL,CREATE_NEW, FILE_ATTRIBUTE_NORMAL,NULL);
	if((HANDLE)filehandle == INVALID_HANDLE_VALUE){
		errparams = (char**) getMemory(1,PCHAR_TYPE);
		errparams[0] = filename;
		notifyError(ERR_FILE_OPEN, errparams,1,exitonerr);
		errparams[0] = NULL;
		free(errparams);
	}
#else
	filehandle = (void *)getMemory(1,INT_TYPE);
	*(int *)filehandle =open(filename,decodeMode(mode),S_IRWXU);

	if(*(int *)filehandle == -1){
		*(int *)filehandle = open(filename,decodeMode(mode)|O_CREAT,S_IRWXU);
		if(*(int *)filehandle==-1){
			notifyError(ERR_FILE_OPEN, exitonerr, 1, filename);
		}
	}
#endif
	return filehandle;
}



/****************************************************************************
 * @function 		: openOrCreateFile										*
 * @descr			: Apre o crea un file se non esiste. 					*
 * @param filename	: in windows il nome del file da aprire, in unix-like	*
 *					  il nome file corredato del suo path.					*
 * @param mode		: modalita' di apertura dello stream					*
 * @param creatednew: variabile nella quale e' scritto se il file e' nuovo  * 
 *					  meno													*
 * @return			: il filehandle associato al file creato o in caso di	* 
 *					  errore il programma viene terminato in virtu' della	*
 *					  chiamata bloccante a createFile						*
 ****************************************************************************/
void * openOrCreateFile(char *filename, MODE mode, int* creatednew){
	void* filehandle = NULL;

	*creatednew = 0;
	/*Provo ad aprire il file esistente*/
	filehandle = openFile(filename,mode, 0);
	if(filehandle == NULL){
		/*altrimenti lo creo*/
		filehandle = createFile(filename, mode, 1);
		*creatednew = 1;
	}
	return filehandle;
}


/****************************************************************************
 * @function 		: closeFile												*
 * @descr			: chiude un il filehandler di un file.					*
 * @param file		: il filehandler da chiudere							*
 ****************************************************************************/
void closeFile(void *file){
#ifdef _WIN32
	if(!CloseHandle((HANDLE)file)){
			notifyError(ERR_FILE_CLOSE,NULL,0,1);
	}
#else
	if(close(*((int*)file)) == -1){
		notifyError(ERR_FILE_CLOSE, 1, 0);
	}
#endif
}

int countFileBytes(void * filehandle){
	char * buffer = NULL;
	unsigned long readbytes = 1L;
	int counter = 0;

	//logMessage(DBG_LEV,"commons.readAllFile() START");
	while(readbytes>0){
		buffer = readFileBlock(filehandle, &readbytes);
		if(readbytes > 0 && buffer != NULL){
			counter = counter + strlen(buffer);
			free(buffer);
			buffer = NULL;
		}
		if(buffer != NULL){
			free(buffer);
			buffer = NULL;
		}
	}
	return counter;
}



char * readFileLine(void * filehandle, int * seek){
	char * content = NULL;
	char* buffer = NULL;
	unsigned long *readbytes;
	char * temp = NULL;
	int size = 0;

	readbytes = (unsigned long *) getMemory(1,ULONG_TYPE);
	*readbytes = 0L;

	buffer = readFileByte(filehandle, readbytes);
	while(*readbytes>0 && buffer != NULL
				&& *buffer!='\r' && *buffer!='\0'){
		if(content != NULL){
			size = strlen(content)+1;
			temp = content;
			size = strlen(temp)+*readbytes+1;
			content = (char *)getMemory(size,CHAR_TYPE);
			memset(content,'\0',size);
			strcat (content,temp);
			strcat (content,buffer);
			free(temp);
			temp = NULL;
		}

		else{
			content = (char *)getMemory(*readbytes+1,CHAR_TYPE);
			memset(content,'\0',*readbytes+1);
			strcat (content,buffer);

		}

//		*seek += *readbytes+2;
		free(buffer);
		buffer = NULL;
		buffer = readFileByte(filehandle, readbytes);
	}
	if(*buffer == '\r'){
		//Leggo \n
		buffer = readFileByte(filehandle, readbytes);
		*readbytes = *readbytes+1;
	}
	*seek += *readbytes;
	free(buffer);
	buffer = NULL;
	if(content != NULL){
		buffer = content;
		content = (char *) getMemory(strlen(buffer)+3, CHAR_TYPE);
		memset(content,'\0', strlen(buffer)+3);
		strcat(content, buffer);
		strcat(content, "\r\n");
		free(buffer);
		buffer = NULL;
	}
	return content;
}

/****************************************************************************
 * @function 		: readAllFile											*
 * @descr			: Legge l'intero contenuto di un file in un array di	*
 *					  caratteri. La lettura � bufferizzata a 63 caratteri	*
 *					  per volta dalla chiamata a readFileBlock				*
 * @param filehandle: il filehandler del file da leggere					*
 * @return			: un puntatore alla stringa contenuto del file.			*
 *					  Se nulla viene letto ritorna la stringa vuota.		* 
 ****************************************************************************/
char * readAllFile(void * filehandle){
	char * content = NULL;
	char * buffer = NULL;
	unsigned long readbytes = 1L;
	char * temp = NULL;


	do{
		buffer = readFileBlock(filehandle, &readbytes);
		if(readbytes > 0 && buffer != NULL){
			if(content != NULL){
				temp = content;
				content = (char *)getMemory(strlen(temp)+strlen(buffer)+1,CHAR_TYPE);
				memset(content,'\0',strlen(temp)+strlen(buffer)+1);
				strcat(content,temp);
				strcat(content,buffer);
				free(temp);
				temp = NULL;
			}
			else{
				content = (char *)getMemory(strlen(buffer)+1,CHAR_TYPE);
				memset(content,'\0',strlen(buffer)+1);
				strcpy(content,buffer);
			}
		}
		if(buffer != NULL){
			free(buffer);
			buffer = NULL;
		}
	}while(readbytes>0);
	if(temp != NULL){
		free(temp);
		temp = NULL;
	}
	return content;
}


/****************************************************************************
 * @function 		: readFileBlock											*
 * @descr			: Legge un blocco di 63 caratteri da un file e lo		*
 *					  concatena col carattere terminatore di stringa '\0'	*
 *					  caratteri. 											*
 * @param filehandle: il filehandler del file da leggere					*
 * @param bytesread	: area di memoria in cui tornare il numero di bytes		*
 *					  letti.												*
 * @return			: un puntatore alla stringa letta dal file.				*
 *					  Se nulla viene letto ritorna la stringa vuota.		*
 *					  La gestione degli errori e' demandata alla notifyerror* 
 ****************************************************************************/
char * readFileBlock(void * filehandle, unsigned long * bytesread){
	
	char * buffer = NULL;
	/*Alloco 64 byte. Il 64mo e' riservato per '\0'*/
	buffer = (char *)getMemory(64,CHAR_TYPE);
	memset(buffer,'\0',64);
	*bytesread = 0;
	#ifdef _WIN32
	//LPDWORD readbytes = (LPDWORD)getMemory(1,LPDWORD_TYPE);
	if(ReadFile((HANDLE)filehandle, buffer, 63,bytesread,NULL)==0){
		notifyError(ERR_FILE_READ,NULL,0,1);
	}
	#else
	if((*bytesread = (unsigned long) read(*(int*)filehandle, buffer, 63))<0){
		notifyError(ERR_FILE_READ, 1, 0);
	}
	#endif
	return buffer;
}


char *readFileByte(void * filehandle, unsigned long * bytesread){

	char *buffer = NULL;
	*bytesread = 0;
	/*Chiedo due byte per leggerne 1. l'ultimo è riservato a '\0'*/
	buffer = (char *)getMemory(2,CHAR_TYPE);
	memset(buffer,'\0',2);
	#ifdef _WIN32
	//LPDWORD readbytes = (LPDWORD)getMemory(1,LPDWORD_TYPE);
	if(ReadFile((HANDLE)filehandle, &buffer, 1,bytesread,NULL)==0){
		free(buffer);
		notifyError(ERR_FILE_READ,NULL,0,1);
	}
	#else
	if((*bytesread = (unsigned long) read(*(int*)filehandle, buffer, 1))<0){
		if(buffer != NULL){
			free(buffer);
			buffer = NULL;
		}
		notifyError(ERR_FILE_READ, 1, 0);
	}
	#endif
	return buffer;
}


/****************************************************************************
 * @function 		: writeFile												*
 * @descr			: Scrive un array di caratteri su di un file,			*
 *					  bufferizzando la scrittura a 64 bytes alla volta.		*
 *					  La gestione degli errori e' demandata alla notifyerror* 
 * @param filehandle: il filehandler del file da scrivere					*
 * @param content	: l'array a caratteri da scrivere						*
 ****************************************************************************/
void writeFile(void *filehandle, char * content){

	int i;
	int contentsize = 0;
	int wCycles = 0;
	int lastbytes = 0;
	char buffer[64];
#ifdef _WIN32
	unsigned long * writtenbytes = (unsigned long *)getMemory(1,ULONG_TYPE);
	memset(buffer,'\0',64);
#endif
	
	if(isNull(content)==1||isNull(filehandle)==1){
		notifyError(ERR_FILE_WRITE,1, 0);
	}

	contentsize = strlen(content);
	wCycles = contentsize == 0 ? 0 : contentsize/64;
	lastbytes = contentsize == 0 ? 0 : contentsize%64;
	
	i=0;
	while(wCycles > 0){
		memset(buffer,'\0',64);
		strncpy(buffer, &content[i],64);
		#ifdef _WIN32
			if(!WriteFile((HANDLE)filehandle,buffer,64,writtenbytes,NULL)){		
				notifyError(ERR_FILE_WRITE,NULL,0,1);
			}
		#else
			if(write(*(int *)filehandle, buffer,64) == -1){
				notifyError(ERR_FILE_WRITE,1,0);
			}
		#endif
			i+=64;
		wCycles--;
	}

	if(lastbytes > 0 ){
		memset(buffer,'\0',64);
		strncpy(buffer, &content[i],lastbytes);
		//buffer[lastbytes] = '\0';
#ifdef _WIN32
		if(!WriteFile((HANDLE)filehandle,buffer,lastbytes,writtenbytes,NULL)){
			notifyError(ERR_FILE_WRITE,NULL,0,1);
		}
#else
		if(write(*(int *)filehandle, buffer,lastbytes) == -1){
			notifyError(ERR_FILE_WRITE,1,0);
		}
#endif
	}
#ifdef _WIN32
	FlushFileBuffers(filehandle);
#endif
}



/*
  Match the string in "to_match" against the compiled regular
  expression in "r".
 */

int match_regex (regex_t * r, const char * to_match, const char * regex_text){
	char param[] = {0};
	int start = 0, finish = 0, i = 0, match_res = -10;
	/* "P" is a pointer into the string which points to the end of the
       previous match. */
    const char * p = to_match;
    /* "N_matches" is the maximum number of matches allowed. */
    const int n_matches = 1;
    /* "M" contains the matches found. */
    regmatch_t m[n_matches];
    int status = regcomp (r, regex_text, REG_EXTENDED|REG_NEWLINE);
    if (status != 0) {
		regerror(status, r, param, 128);
		notifyError(ERR_CFG_READ, 0, 0, param);
		return REG_NOMATCH;
	}

	match_res = regexec (r, p, n_matches, m, 0);
	if (match_res==0) {
		return match_res;
	}

	if (m[i].rm_so == -1) {
		return REG_NOMATCH;
	}
	start = m[i].rm_so + (p - to_match);
	finish = m[i].rm_eo + (p - to_match);

	if(start !=0 || finish+1 != strlen(to_match)){
		return REG_NOMATCH;
	}

    return match_res;
}

int isStringInSet(char** set, char* stringToFind){
	int k= 0;
	if(set != NULL && stringToFind!= NULL){

		while(set[k]!=NULL){
			if(strcasecmp(set[k], stringToFind)==0){
				return 1;
			}
			k++;
		}

	}
	return 0;
}

char * substituteString(char *string, char * patternToFind, char* subsitutePattern){
	int k, size;
	char * token = NULL;
	char * tmp = NULL;
	if(string == NULL || patternToFind == NULL || subsitutePattern == NULL){
		return NULL;
	}
	k=0;

	do{
		token = (char *)getMemory(strlen(patternToFind)+1, CHAR_TYPE);
		memset(token,'\0',strlen(patternToFind)+1);
		strncpy(token,&string[k],strlen(patternToFind));
		if(strcasecmp(token,patternToFind)==0){
			tmp = string;
			size = strlen(string)+2;
			string = (char *)getMemory(size,CHAR_TYPE);
			memset(string,'\0',size);
			//AAAA
			strncpy(string, &tmp[0], k);
			strcat(string,subsitutePattern);
			strcat(string, &tmp[k+strlen(patternToFind)]);
			k += strlen(patternToFind);
			free(tmp);
			tmp = NULL;
		}
		free(token);
		token = NULL;
		while(string[k-1]!='\r' && string[k]!= '\n') k++;
		//k e' sul '\n'
		k++;

	}while(string[k]!='\0');

	return string;

}

char * removeAngParenthesys (char content[]){
	int length = 0, start = 0, end = 0;
	char *tmp = NULL;

	if(content != NULL){
		length = strlen(content);
		end = length;
		if(content[0]=='<'){
			start = 1;
		}
		if(content[length-1]=='>'){
			end--;
		}

		if(start > 0 || end < length){
			tmp = content;
			content = (char *)getMemory(end-start+1, CHAR_TYPE);
			memset(content, '\0', end-start+1);
			strncpy(content, &tmp[start], end-start);
			free(tmp);
			tmp = NULL;
		}
	}
	return content;
}
